package com.hts.utils.stream;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

/**
 * Streams就是stream 流的一些操作
 *
 * @author hs
 * @version 1.0
 * @date: 2023/2/16
 */
public class Streams {
public void tetst(){
    System.out.println();
}
    public static <T> int getIndex(List<T> collection,Predicate<T> predicate){
        if(CollUtil.isEmpty(collection)){
            return -1;
        }
        for (int i = 0; i < collection.size(); i++) {
            T t = collection.get(i);
            if(predicate.test(t)){
                return i;
            }
        }
        return -1;
    }

    /**
     * 不包含
     * @param t
     * @param r
     * @param predicate
     * @return
     * @param <T>
     * @param <R>
     */
    public static <T,R> List<T>  noContain(List<T>t,List<R> r,BiPredicate<T,R> predicate){
        if(CollUtil.isEmpty(t) && CollUtil.isEmpty(r)){
            return t;
        }
        return t.stream().filter(t1->r.stream().noneMatch(r1->predicate.test(t1,r1))).collect(Collectors.toList());
    }

    /**
     * 包含
     * @param t
     * @param r
     * @param predicate
     * @return
     * @param <T>
     * @param <R>
     */

    public static <T,R> List<T>  contain(List<T>t,List<R> r,BiPredicate<T,R> predicate){
        if(CollUtil.isEmpty(t) && CollUtil.isEmpty(r)){
            return t;
        }
        return t.stream().filter(t1->r.stream().anyMatch(r1->predicate.test(t1,r1))).collect(Collectors.toList());
    }



    public static <T,R> boolean isSame(Collection<T> listOne , Collection<R>listTwo, BiPredicate<T,R> predicate){
        if(CollUtil.isEmpty(listOne) && CollUtil.isEmpty(listTwo)){
            return true;
        }
        if (listOne.size() != listTwo.size()) {
            return false;
        }

        return listOne.stream().allMatch(one->
                listTwo.stream().anyMatch(two-> predicate.test(one, two))
        );


    }
    /**
     * 获取集合
     *
     * @param list
     * @param function
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> toList(Collection<T> list, Function<T, R> function) {
        return list == null ? null : list.stream().map(function).collect(Collectors.toList());
    }


    /**
     * 获取集合 非空处理
     *
     * @param list
     * @param function
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> toNoNullList(Collection<T> list, Function<T, R> function) {
        return list == null ? null : list.stream().map(function).filter(o -> !Objects.isNull(o)).collect(Collectors.toList());
    }

    /**
     * 去重
     *
     * @param list
     * @param function
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> toListDistinct(Collection<T> list, Function<T, R> function) {
        return list == null ? null : list.stream().map(function).distinct().collect(Collectors.toList());
    }

    public static <T, R> Set<R> toSet(Collection<T> list, Function<T, R> function) {
        return list == null ? null : list.stream().map(function).collect(Collectors.toSet());
    }

    public static <T, R> List<T> filter(List<T> list, Predicate<T> function) {
        return list == null ? null : list.stream().filter(function).collect(Collectors.toList());
    }

    public static <T, R> List<R> filter(List<T> list, Predicate<T> predicate, Function<T, R> function) {
        return list == null ? null : list.stream().filter(predicate).map(function).collect(Collectors.toList());
    }

    public static <T, R> Integer count(List<T> list, Predicate<T> function) {
        return list == null ? null : Long.valueOf(list.stream().filter(function).count()).intValue();
    }

    /**
     * 分组
     *
     * @param list
     * @param function
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> Map<R, List<T>> groupBy(List<T> list, Function<T, R> function) {
        return list == null ? null : list.stream().collect(Collectors.groupingBy(function));
    }

    /**
     * 分组 操作俩次 分组    第二次 分组更具value 分组
     * @param list
     * @param function
     * @param tzFunction
     * @return
     * @param <T>
     * @param <R>
     * @param <Z>
     */
    public static <T, R, Z> Map<R, Map<Z, List<T>>> groupBy(List<T> list, Function<T, R> function, Function<T, Z> tzFunction) {
        return list == null ? null : list.stream().collect(Collectors.groupingBy(function, Collectors.groupingBy(tzFunction)));
    }


    public static <T, R> Map<R, T> toMap(List<T> list, Function<T, R> function) {
        return list == null ? null : list.stream().collect(Collectors.toMap(function, Function.identity()));
    }

    public static <T, R, U> Map<R, U> toMap(List<T> list, Function<T, R> key, Function<T, U> value) {
        return list == null ? null : list.stream().collect(Collectors.toMap(key, value));
    }

    /**
     * 返回map 默认去掉value 未空的数据
     *
     * @param list
     * @param key
     * @param value
     * @param <T>
     * @param <R>
     * @param <U>
     * @return
     */
    //不支持并发流
    public static <T, R, U> Map<R, U> toAutoMergeMap(List<T> list, Function<T, R> key, Function<T, U> value) {
        return list == null ? null : list.stream().filter(t -> value.apply(t) != null).collect(Collectors.toMap(key,
                value, (m1, m2) -> m1,
                HashMap::new)
        );
    }

    public static <T, R> Map<R, T> toAutoMergeMap(List<T> list, Function<T, R> key) {

        return list == null ? null : list.stream().filter(Objects::nonNull).collect(Collectors.toMap(key,
                Function.identity(), (m1, m2) -> m1,
                HashMap::new)
        );
    }

    /**
     * 返回LinkedHashMap 默认去掉value 未空的数据
     *
     * @param list
     * @param key
     * @param value
     * @param <T>
     * @param <R>
     * @param <U>
     * @return
     */
    //不支持并发流
    public static <T, R, U> Map<R, U> toAutoMergeLinkMap(List<T> list, Function<T, R> key, Function<T, U> value) {
        return list == null ? null : list.stream().filter(t -> value.apply(t) != null).collect(Collectors.toMap(key,
                value, (m1, m2) -> m1,
                LinkedHashMap::new)
        );
    }

    public static <T, R, U> String join(List<T> list, Function<T, String> function, String joinString) {
        return list == null ? null : list.stream().map(function).collect(Collectors.joining(joinString));
    }

    public static <T, R> List<R> copyList(List<T> list, Class<R> tClass, Consumer<R> consumer) {
        return list == null ? null : list.stream().map(t -> {
            R r = BeanUtil.copyProperties(t, tClass);
            consumer.accept(r);
            return r;
        }).collect(Collectors.toList());
    }

    public static <T, R> List<R> copyList(List<T> list, Class<R> tClass, BigConsumer<T, R> consumer) {
        return list == null ? null : list.stream().map(t -> {
            R r = BeanUtil.copyProperties(t, tClass);
            consumer.accept(t, r);
            return r;
        }).collect(Collectors.toList());
    }


    /**
     * 结果处理 boolean 处理 所有的 and 处理
     *
     * @param list     集合
     * @param function 获取集合 Boolean 属性
     * @param <T>
     * @return 所有集合的总
     */
    public static <T> Boolean booleanCount(List<T> list, Function<T, Boolean> function) {
        return list == null ? null : list.stream().map(function).reduce(Boolean.TRUE, (s1, s2) -> s1 && s2);
    }

    /**
     * Boolean 结果汇总
     *
     * @param list        处理的集合数据
     * @param function    获取属性类型为boolean 的值
     * @param accumulator 一种用于组合两个值的关联的操作
     * @param <T>
     * @return boolean的总和
     */
    public static <T> Boolean booleanCount(List<T> list, Function<T, Boolean> function, BinaryOperator<Boolean> accumulator) {
        return list == null ? null : list.stream().map(function).reduce(Boolean.TRUE, accumulator);
    }

    /**
     * 集合书信 BigDecimal 所有相加
     *
     * @param list     集合数据
     * @param function 获取集合中元素的成员变量 类型为BigDecimal 的值
     * @param <T>
     * @return 所有元素相加的值
     */
    public static <T> BigDecimal bigDecimalCount(List<T> list, Function<T, BigDecimal> function) {
        return list == null ? null : list.stream().map(function).reduce(BigDecimal.ZERO, BigDecimal::add);
    }



    /**
     * 自定义函数是声明接口 用户入参俩参数消费
     *
     * @param <T> 消费者1
     * @param <R> 消费者2
     */
    @FunctionalInterface
    public static interface BigConsumer<T, R> {
        void accept(T t, R r);
    }
}
